package ltd.bugs.tool.signature.factory.impl;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Map;

import ltd.bugs.tool.signature.attribute.SignatureAttribute;
import ltd.bugs.tool.signature.factory.Signature;
import ltd.bugs.tool.signature.utils.ExtraUtils;
import ltd.bugs.tool.signature.utils.StringUtils;

/**
 * @author zhengzhq
 * @Title: CompanyGeneralSignature
 * @Dscription: 公司通用签章实现
 * @date 2018/8/9下午5:31
 */
public class CompanyGeneralSignature implements Signature {

  public BufferedImage draw(Font font, Color color, int width, int height,
                            Map<String, Object> extras) {
    String name = ExtraUtils.getAttributeValue(extras, SignatureAttribute.SIGNATURE_TEXT,
            String.class);
    if (StringUtils.isEmpty(name)) {
      throw new IllegalArgumentException("name can't be empty!");
    }
    int borderFix = ExtraUtils.getAttributeValue(extras, SignatureAttribute.BORDER_FIX,
            Integer.class, 5);
    float starRadius = ExtraUtils.getAttributeValue(extras, SignatureAttribute.STAR_RADIUS,
            Float.class, 40f);
    int starBorderWidth = ExtraUtils.getAttributeValue(extras, SignatureAttribute.STAR_BORDER_WIDTH,
            Integer.class, 3);
    int borderWidth = ExtraUtils.getAttributeValue(extras, SignatureAttribute.BORDER_WIDTH,
            Integer.class, 3);
    int nameOffset = ExtraUtils.getAttributeValue(extras, SignatureAttribute.NAME_OFFSET,
            Integer.class, 50);
    // 五角星的颜色和整个字体布局颜色一致
    Color starColor = color;
    Color borderColor = ExtraUtils.getAttributeValue(extras, SignatureAttribute.BORDER_COLOR,
            Color.class, color);
    String firm = ExtraUtils.getAttributeValue(extras, SignatureAttribute.FIRM,
            String.class);
    Font firmFont = ExtraUtils.getAttributeValue(extras, SignatureAttribute.FIRM_FONT,
            Font.class, font);
    String license = ExtraUtils.getAttributeValue(extras, SignatureAttribute.LICENCE,
            String.class);
    Font licenseFont = ExtraUtils.getAttributeValue(extras, SignatureAttribute.LICENCE_FONT,
            Font.class, font);
    //印章所属单位的起始角度,以6点钟方向为中心,向两个方向平均扩展
    float firmAngle = 120;
    //单位字体的宽度缩放比率(百分比).此参数可以使字体看起来瘦长
    float firmScale = 1.0F;
    //许可证号、角度范围、颜色、字体
    float licenseAngle = 90;
    float licenseScale = 1.0F;

    BufferedImage image = new BufferedImage(width + borderFix * 2, height + borderFix * 2,
            BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = image.createGraphics();
    g2d.translate(borderFix, borderFix);

    g2d.translate(width / 2, height / 2);// 把绘制起点挪到圆中心点
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    Stroke stroke = g2d.getStroke();// 旧的线性
    Polygon polygon = getPentaclePoints(starRadius);
    if (starColor != null) {// 填充五角星
      g2d.setColor(starColor);
      g2d.fill(polygon);
    }

    // 绘制五角星边框
    g2d.setStroke(new BasicStroke(starBorderWidth));
    g2d.setColor(starColor);
    g2d.draw(polygon);

    // 绘制印章边框
    g2d.setColor(borderColor);
    g2d.setStroke(new BasicStroke(borderWidth));
    g2d.drawOval(-width / 2, -height / 2, width, height);
    g2d.setStroke(stroke);

    if (name != null && name.length() > 0) {// 绘制印章名称
      g2d.setFont(font);
      g2d.setColor(color);
      FontMetrics fm = g2d.getFontMetrics();
      int w = fm.stringWidth(name);// 名称宽度
      int h = fm.getHeight();// 名称高度
      int y = fm.getAscent() - h / 2;// 求得中心线经过字体的高度的一半时的字体的起绘点
      g2d.drawString(name, -w / 2, y + nameOffset);
    }

    if (!StringUtils.isEmpty(firm)) {// 绘制印章单位
      g2d.setFont(firmFont);
      g2d.setColor(color);
      FontMetrics fm = g2d.getFontMetrics();
      int h = fm.getHeight();// 字高度

      int count = firm.length();// 字数
      int r = width / 2;// 半径,就假设此印章是个矩形,方便计算

      float angle = (360 - firmAngle) / (count - 1);// 字间角度
      float start = 90 + firmAngle / 2;// 以x轴正向为0,顺时针旋转
      double vr = Math.toRadians(90);// 垂直旋转弧度
      char[] chars = firm.toCharArray();
      for (int i = 0; i < count; i++) {
        char c = chars[i];// 需要绘制的字符
        int cw = fm.charWidth(c);// 此字符宽度
        float a = start + angle * i;// 现在角度

        double radians = Math.toRadians(a);
        g2d.rotate(radians);// 旋转坐标系,让要绘制的字符处于x正轴
        float x = r - h;// 绘制字符的x坐标为半径减去字高度
        // g2d.drawLine(0, 0, (int) x, 0);// debug
        g2d.translate(x, 0);// 移动到此位置,此时字和x轴垂直
        g2d.rotate(vr);// 旋转90度,让字平行于x轴
        g2d.scale(firmScale, 1);// 缩放字体宽度
        g2d.drawString(String.valueOf(c), -cw / 2, 0);// 此点为字的中心点
        // 将所有设置还原,等待绘制下一个
        g2d.scale(1 / firmScale, 1);
        g2d.rotate(-vr);
        g2d.translate(-x, 0);
        g2d.rotate(-radians);
      }
    }

    if (!StringUtils.isEmpty(license)) {//绘制许可证号
      g2d.setFont(licenseFont);
      g2d.setColor(color);
      FontMetrics fm = g2d.getFontMetrics();
      int h = fm.getHeight();// 字高度
      int count = license.length();
      int r = width / 2 + font.getSize();
      float angle = licenseAngle / (count - 1);
      float start = 90 + licenseAngle / 2;
      double vr = Math.toRadians(270);

      char[] chars = license.toCharArray();
      for (int i = 0; i < count; i++) {
        char c = chars[i];// 需要绘制的字符
        int cw = fm.charWidth(c);// 此字符宽度
        float a = start - angle * i;// 现在角度

        double radians = Math.toRadians(a);
        g2d.rotate(radians);// 旋转坐标系,让要绘制的字符处于x正轴
        float x = r - h;// 绘制字符的x坐标为半径减去字高度
        g2d.translate(x, 0);// 移动到此位置,此时字和x轴垂直
        g2d.rotate(vr);// 旋转90度,让字平行于x轴
        g2d.scale(licenseScale, 1);// 缩放字体宽度
        g2d.drawString(String.valueOf(c), -cw / 2, 0);// 此点为字的中心点
        // 将所有设置还原,等待绘制下一个
        g2d.scale(1 / licenseScale, 1);
        g2d.rotate(-vr);
        g2d.translate(-x, 0);
        g2d.rotate(-radians);
      }
    }
    return image;
  }

  /**
   * 获取具有指定半径外接圆的五角星顶点
   */
  private Polygon getPentaclePoints(float radius) {
    float lradius = radius * 0.381966f;// 根据radius求内圆半径
    double halfpi = Math.PI / 180f;
    Point[] points = new Point[10];
    for (int i = 0; i < points.length; i++) {
      if (i % 2 == 1)
        points[i] = new Point(
                (int) (Math.sin(halfpi * 36 * i) * radius),
                (int) (Math.cos(halfpi * 36 * i) * radius));
      else
        points[i] = new Point(
                (int) (Math.sin(halfpi * 36 * i) * lradius),
                (int) (Math.cos(halfpi * 36 * i) * lradius));
    }
    Polygon polygon = new Polygon();
    for (Point p : points) {
      polygon.addPoint(p.x, p.y);
    }

    return polygon;
  }
}
